package se.topshelf.golftracker.core.domain;

import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;

import javax.persistence.*;
import javax.print.DocFlavor;
import javax.validation.constraints.NotNull;
import java.util.SortedSet;
import java.util.TreeSet;

/**
 *
 */
@Entity
@Table(name = "Round")
public class Round extends BaseEntity implements Comparable<Round> {

    @NotNull
    @ManyToOne
    @JoinColumn(name = "teeTimeId")
    private TeeTime teeTime;

    @NotNull
    @ManyToOne
    @JoinColumn(name = "playerId")
    private Player player;


    @NotNull
    @Enumerated(EnumType.STRING)
    private TeeColour teeColour;

    @NotNull
    @OneToMany(mappedBy = "round", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
    @Sort(type = SortType.NATURAL)
    private SortedSet<HoleResult> holeResults = new TreeSet<HoleResult>();

    public Round() {
    }

    public Round(Player player, TeeColour teeColour) {
        this.player = player;
        this.teeColour = teeColour;
    }

    /**
     * @return The total score for this round, as accumulated by its hole results.
     */
    public Integer getTotalScore() {
        Integer totalScore = 0;
        for (HoleResult currHoleResult : holeResults) {
            totalScore += currHoleResult.getScore();
        }
        return totalScore;
    }

    public Integer getTotalNetScore() {
        // ToDo Add support to calculated given shots for a player given the a) the course and b) tee colour.
        // This information should ideally be stored by the course
        return getTotalScore() - player.getHandicap().intValue();
    }

    public Double getSlopeHandicap(){
        // ToDo This should be set up just before adding this round taking into to account slope, handicap, tee box
        return player.getHandicap();
    }

    public Player getPlayer() {
        return player;
    }

    public void setPlayer(Player player) {
        this.player = player;
    }

    public TeeTime getTeeTime() {
        return teeTime;
    }

    public void setTeeTime(TeeTime teeTime) {
        this.teeTime = teeTime;
    }

    public TeeColour getTeeColour() {
        return teeColour;
    }

    public void setTeeColour(TeeColour teeColour) {
        this.teeColour = teeColour;
    }

    public SortedSet<HoleResult> getHoleResults() {
        return holeResults;
    }

    public HoleResult createAndAddHoleResultFrom(Hole hole){
        HoleResult holeResult = new HoleResult(hole, this);
        return addHoleResult(holeResult);
    }

    public HoleResult addHoleResult(HoleResult holeResult) {
        if (holeResults.contains(holeResult)) {
             throw new IllegalArgumentException("");
        }
        holeResult.setRound(this);
        holeResults.add(holeResult);
        return holeResult;
    }

    public void setHoleResults(SortedSet<HoleResult> holeResults) {
        this.holeResults = holeResults;
    }

    public int compareTo(Round o) {
        int teeTimeCompare = teeTime.compareTo(o.getTeeTime());
        if (teeTimeCompare == 0) {
            return player.compareTo(o.getPlayer());
        }
        return teeTimeCompare;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Round round = (Round) o;

        if (!player.equals(round.player)) return false;
        if (!teeTime.equals(round.teeTime)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = player.hashCode();
        result = 31 * result + teeTime.hashCode();
        return result;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("Round");
        sb.append("{player=").append(player);
        sb.append(", teeTime=").append(teeTime);
        sb.append('}');
        return sb.toString();
    }
}
